﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace SwiftMVVM.Behaviors
{
    /// <summary>
    /// Controls the auto select style of the TextBox when the user sets focus to it
    /// </summary>
    public enum AutoSelectAllBehavior
    {
        None,
        FocusOrMouseClick
    }

    /// <summary>
    /// TextBoxBehavior defines a set of reusable behaviors normally coded against a textbox.
    /// Such as AutoSelection on focus.
    /// </summary>
    public sealed class TextBoxBehavior
    {
        /// <summary>
        /// AutoScrollToEnd Dependency property declaration
        /// </summary>
        public static readonly DependencyProperty AutoScrollToEndProperty =
           DependencyProperty.RegisterAttached(
           "AutoScrollToEnd",
           typeof(bool),
           typeof(TextBoxBehavior),
           new FrameworkPropertyMetadata(false, (d, e) =>
           {
               var textBox = d as TextBox;
               if (textBox != null)
               {
                   if (e.NewValue != null &&
                       ((bool)e.NewValue) == true)
                   {
                       textBox.AddHandler(TextBox.TextChangedEvent,
                           new TextChangedEventHandler((sender, textChangedArgs) =>
                           {
                               ((TextBox)sender).ScrollToEnd();
                           }), true);
                   }
               }
           })
           );

        /// <summary>
        /// AutoScrollToEnd dependency property getter
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool GetAutoScrollToEnd(DependencyObject obj)
        {
            return (bool)obj.GetValue(AutoScrollToEndProperty);
        }

        /// <summary>
        /// AutoScrollToEnd dependency property setter
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        public static void SetAutoScrollToEnd(DependencyObject obj, bool value)
        {
            obj.SetValue(AutoScrollToEndProperty, value);
        }

      

        /// <summary>
        /// AutoSelectAll Dependency property declaration
        /// </summary>
        public static readonly DependencyProperty AutoSelectAllProperty =
           DependencyProperty.RegisterAttached(
           "AutoSelectAll",
           typeof(AutoSelectAllBehavior),
           typeof(TextBoxBehavior),
           new FrameworkPropertyMetadata(AutoSelectAllBehavior.None, AutoSelectAllChangedCallback)
           );

        /// <summary>
        /// AutoSelectAll dependency property getter
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static AutoSelectAllBehavior GetAutoSelectAll(DependencyObject obj)
        {
            return (AutoSelectAllBehavior)obj.GetValue(AutoSelectAllProperty);
        }

        /// <summary>
        /// AutoSelectAll dependency property setter
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        public static void SetAutoSelectAll(DependencyObject obj, AutoSelectAllBehavior value)
        {
            obj.SetValue(AutoSelectAllProperty, value);
        }

        /// <summary>
        /// Fired when the AutoSelectAll behavior property changes
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void AutoSelectAllChangedCallback(DependencyObject d,
                            DependencyPropertyChangedEventArgs e)
        {
            var textBox = d as TextBox;
            if (textBox != null)
            {
                if (e.NewValue != null &&
                    ((AutoSelectAllBehavior)e.NewValue) == AutoSelectAllBehavior.FocusOrMouseClick)
                {
                    textBox.AddHandler(TextBox.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(SelectivelyIgnoreMouseButton), true);
                    textBox.AddHandler(TextBox.GotKeyboardFocusEvent, new RoutedEventHandler(SelectAllText), true);
                    textBox.AddHandler(TextBox.MouseDoubleClickEvent, new RoutedEventHandler(SelectAllText), true);
                }
            }
        }

        /// <summary>
        /// Selects all the text in the textbox this behavior is attached to
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void SelectAllText(object sender, RoutedEventArgs e) 
        {
            var textBox = e.OriginalSource as TextBox;
            if (textBox != null)
            {
                textBox.SelectAll();
            }
        }

        /// <summary>
        /// Focuses the textbox on click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private static void SelectivelyIgnoreMouseButton(object sender, MouseButtonEventArgs e)
        {
            // Find the TextBox
            DependencyObject parent = e.OriginalSource as UIElement;

            while (parent != null && !(parent is TextBox))
            {
                parent = VisualTreeHelper.GetParent(parent);  
            }

            if (parent != null)       
            {            
                var textBox = (TextBox)parent;  
                if (!textBox.IsKeyboardFocusWithin)
                {                
                    // If the text box is not yet focussed, give it the focus and         
                    // stop further processing of this click event.               
                    textBox.Focus();              
                    e.Handled = true;           
                }     
            }   
        }
    }
}
